/*
 * Random.cpp
 *
 *  Created on: 2011/09/04
 *      Author: naoki
 */

#include "StdAfx.h"
#include "NTEngine/Math/Random.h"
#include "NTEngine/Base/ReferenceCounter.h"

namespace NTEngine {
namespace Math {

class Random::Impl : public ReferenceCounter {
public:
	Impl( int seed ) {
		setSeed( seed );
	}

	//
	int nextInt() {
		unsigned long t = mX ^ ( mX << 11 );
		mX = mY;
		mY = mZ;
		mZ = mW;
		return static_cast< int >( mW = ( mW ^ ( mW >> 19 ) ) ^ ( t ^ ( t >> 8 ) ) );
	}

	//
	int nextInt( int a ) {
		return ( nextInt() & 0x7fffffff ) % a;
	}

	//
	float nextFloat() {
		int x = ( nextInt() & 0x007FFFFF ) | 0x3F800000; //指数部に固定で127をぶっこむ
		return *reinterpret_cast< float* >( &x ) - 1.F; // 無理やりキャスト
	}

	// Seedの設定
	void setSeed( int seed ) {
		mX = 123456789UL;
		mY = 362436069UL;
		mZ = 521288629UL;
		mW = (seed <= 0) ? 88675123UL : static_cast<unsigned long>(seed);
	}
private:
	unsigned long mX;
	unsigned long mY;
	unsigned long mZ;
	unsigned long mW;
};

Random Random::create( int seed ) {
	Random ret;
	ret.mImpl = NEW Impl( seed );
	return ret;
}

int Random::nextInt() {
	return mImpl->nextInt();
}

int Random::nextInt( int a ) {
	return mImpl->nextInt( a );
}

float Random::nextFloat() {
	return mImpl->nextFloat();
}

void Random::setSeed( int seed ) {
	mImpl->setSeed( seed );
}

#define TYPE Random
#include "NTEngine/Base/Impl/ReferenceCounterTemplate.h"

} // namespace Math
} // namespace NTEngine
